package com.efeichong.common.config;

import com.efeichong.common.domain.ResponseData;
import com.efeichong.common.domain.entity.redis.LoginUser;
import com.efeichong.common.security.LoginContextHolder;
import com.efeichong.common.utils.NetworkUtil;
import com.efeichong.common.utils.json.JsonUtils;
import com.google.common.base.Charsets;
import com.google.common.base.Stopwatch;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URLDecoder;
import java.security.Principal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author : lxk
 * @Date : 2022/7/26
 * @Description : 通过aop切出controller日志
 */
@Component
@Aspect
@Slf4j
public class LogControllerAspect {

    @SneakyThrows
    @Around("execution(public * com..controller..*.*(..))")
    public Object recordTimeLog(ProceedingJoinPoint joinPoint) {
        Stopwatch stopwatch = Stopwatch.createStarted();
        //获取请求会话管理。
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String queryString = decode(request.getQueryString());
        String url = request.getMethod() + ":" + request.getRequestURL().toString() + "?" + queryString;
        String ipAddress = NetworkUtil.getIpAddress(request);
        MDC.put("ip", ipAddress);
        LoginUser loginUser = LoginContextHolder.getLoginUser();
        if (loginUser != null) {
            MDC.put("userId", loginUser.getId() + "");
        } else {
            MDC.put("userId", "未登录");
        }

        List<Object> params = new ArrayList<Object>(joinPoint.getArgs().length);
        for (Object param : joinPoint.getArgs()) {
            if (param != null) {
                if (param instanceof MultipartFile || param instanceof MultipartFile[]) {
                    params.add("上传文件内容");
                } else if (param instanceof HttpServletResponse) {
                    params.add("servletResponse对象");
                } else if (param instanceof HttpServletRequest) {
                    params.add("servletRequest对象");
                } else if (param instanceof Principal) {
                    params.add("登录用户对象");
                } else {
                    params.add(param);
                }
            }
        }
        log.info("{}:访问方法 :{} 请求参数:{}", url, joinPoint.getSignature().getDeclaringTypeName() + "."
                + joinPoint.getSignature().getName(), JsonUtils.toJson(params));

        Object responseData = joinPoint.proceed();

        long elapsed = stopwatch.elapsed(TimeUnit.MILLISECONDS);
        if (responseData == null) {
            log.info("返回数据为空,请求时间: {}");
        } else if (responseData instanceof ResponseData) {
            ResponseData bean = (ResponseData) responseData;
            log.info("返回数据操作状态为:{},返回信息为:{},请求时间: {}", bean.getStatus(), bean.getMessage(), elapsed);
        } else {
            log.info("返回数据非常用类型数据,请求时间: {}", elapsed);
        }
        return responseData;
    }

    @SneakyThrows
    private String decode(String queryString) {
        if (queryString == null) {
            return "";
        } else {
            return URLDecoder.decode(queryString, Charsets.UTF_8.name());
        }
    }

}
